﻿#region Usings

using System;
using System.Collections;
using System.Reflection;

using Gonte.Collections;
using Gonte.Reflection;
using System.Xml.Serialization; 

#endregion

namespace Gonte.Xml.Serialization
{
    public class XmlDictionaryDeserializer
        : XmlCollectionDeserializer
    {
        #region Constructors

        protected internal XmlDictionaryDeserializer(Object @object)
            : base(@object)
        {
        }

        #endregion

        #region Overridables

        protected override Object CreateItem()
        {
            Object parent = context_.Parent;
            PropertyInfo propertyInfo = parent.GetType().GetProperty(context_.PropertyName);

            attribute_ = CustomAttribute.GetCustomAttribute<DictionaryItemAttribute>(propertyInfo, false);
            ExceptionThrower.ThrowWhenNull("DictionaryItemAttribute", attribute_);

            Type[] types = ObjectFactory.GetItemTypes((IDictionary)object_, attribute_);
            key_ = ObjectFactory.CreateObject(types[0]); // Create the key

            Type itemType = types[1];

            SetDerivedType(propertyInfo, ref itemType);

            return CreateItem(itemType); // Create the value
        }

        private void SetDerivedType(PropertyInfo propertyInfo, ref Type itemType)
        {
            XmlElementAttribute[] xmlElementAttributes = CustomAttribute.GetCustomAttributes<XmlElementAttribute>(propertyInfo, false);

            if (xmlElementAttributes != null)
            {
                string dataType = Reader["xsi:type"];

                if (!string.IsNullOrEmpty(dataType))
                {
                    foreach (XmlElementAttribute xmlElementAttribute in xmlElementAttributes)
                    {
                        if (xmlElementAttribute.Type != null
                            && xmlElementAttribute.Type.FullName.Equals(dataType))
                        {
                            itemType = xmlElementAttribute.Type;
                            break;
                        }
                    }
                }
            }
        }

        protected override void OnDeserializedItem(Object item)
        {
            DictionaryItemPrimitive itemPrimitive = item as DictionaryItemPrimitive;
            if (itemPrimitive != null)
            {
                // Add it to the dictionary
                ((IDictionary)object_).Add(itemPrimitive.Key, itemPrimitive.Value);

                return;
            }

            key_ = CollectionHelper.GetDictionaryItemKey(item, attribute_);

            // Add it to the dictionary
            ((IDictionary)object_).Add(key_, item);
        } 

        #endregion

        #region Fields

        protected DictionaryItemAttribute attribute_; // The descriptor of the item
        protected Object key_; // The key of the item 

        #endregion
    }
}
